package comp

import (
	"fmt"
	"strings"
)

// 全局函数映射表，用于存储自定义运算符的实现
var FuncLi map[string]CompMark

// 常量：最小变量索引的ASCII值
const Coust_a byte = 97

// 初始化函数，初始化全局函数映射表
func init() {
	FuncLi = make(map[string]CompMark)
}

// 注册自定义运算符及其实现
func RegisterComp(name string, f CompMark) {
	FuncLi[name] = f
}

// 将表达式字符串解析为计算节点树
func NewCompNode(exp string) *CompNode {
	arr := compStringToArray(exp)
	result, _ := createComp(arr)
	return result
}

// 自定义运算符的函数签名
type CompMark func(node *CompNode, et IEvent) int64

// 表示计算节点的结构体
type CompNode struct {
	Obj  string    // 对象名
	Var  string    // 属性或变量名
	Val  int64     // 数值
	Num1 *CompNode // 左操作数
	Mark string    // 运算符
	Num2 *CompNode // 右操作数
}

// 将计算节点转换为字符串表示
func (cn *CompNode) String() string {
	if cn.Mark == "+" || cn.Mark == "-" || cn.Mark == "*" || cn.Mark == "/" || cn.Mark == "%" {
		return "(" + cn.Num1.String() + " " + cn.Mark + " " + cn.Num2.String() + ")"
	} else if cn.Mark == "." {
		return cn.Obj + "." + cn.Var
	} else if cn.Mark != "" {
		return cn.Mark + "(" + cn.Num1.String() + "," + cn.Num2.String() + ")"
	} else if cn.Var != "" {
		return cn.Var
	} else {
		return fmt.Sprint(cn.Val)
	}
}

// 递归计算节点的值
func (cn *CompNode) CompVal(et IEvent) (result int64) {
	switch cn.Mark {
	case "":
		result = et.GetVal(cn)
	case ".":
		result = et.GetObjAttr(cn)
	case "+":
		result = cn.Num1.CompVal(et) + cn.Num2.CompVal(et)
	case "-":
		result = cn.Num1.CompVal(et) - cn.Num2.CompVal(et)
	case "*":
		result = cn.Num1.CompVal(et) * cn.Num2.CompVal(et)
	case "/":
		result = cn.Num1.CompVal(et) / cn.Num2.CompVal(et)
	case "%":
		result = cn.Num1.CompVal(et) % cn.Num2.CompVal(et)
	default:
		if f, ok := FuncLi[cn.Mark]; ok {
			//找到函数
			result = f(cn, et)
		} else {
			fmt.Println(" CompNode Error. Not exist Func ", cn.Mark, ". on CompNode:", cn)
		}
	}
	return
}

// 将表达式字符串分解为运算符和操作数的数组
func compStringToArray(exp string) (result []string) {
	// 去除字符串中的空格
	exp = strings.ReplaceAll(exp, " ", "")
	arr := []rune(exp)
	tmp := NewStringBuilder()
	result = make([]string, 0, len(arr))
	for len(arr) > 0 {
		switch arr[0] {
		case '-', '+', '*', '/', '%', '(', ')', ',':
			if !tmp.IsEmpty() {
				result = append(result, tmp.ToString())
				tmp.Clear()
			}
			result = append(result, string(arr[0]))
		default:
			tmp.AppendRune(arr[0])
		}
		arr = arr[1:]
	}
	if !tmp.IsEmpty() {
		result = append(result, tmp.ToString())
	}
	// fmt.Println(result)
	return
}

// 检查运算符的优先级
// 返回值越小，优先级越高
func checkPriority(mark string) int {
	priority := 10
	switch mark {
	case "+", "-":
		priority = 0
	case "*", "/", "%":
		priority = 1
	}
	return priority
}

// 根据字符串创建一个新的计算节点
// 如果字符串是数值，则创建一个值节点
// 如果字符串包含"."，则创建一个对象属性节点
// 否则，创建一个变量节点
func newComp(v string) *CompNode {
	result := new(CompNode)
	if t, ok := NewString(v).ToInt64(); ok == nil {
		result.Val = t
	} else if index := strings.IndexRune(v, '.'); index >= 0 {
		// 对象的属性变量
		result.Obj = v[:index]
		result.Var = v[index+1:]
		result.Mark = "."
	} else {
		result.Var = v
	}
	return result
}

// 根据运算符和操作数数组生成计算节点树
func createComp(arr []string) (result *CompNode, resarr []string) {
	numsk := make(Stack, 0, 20)
	marksk := make(StackMark, 0, 20)
arrfor:
	for len(arr) > 0 {
		data := arr[0]
		arr = arr[1:]
		if _, ok := FuncLi[data]; ok {
			//找到了函数
			//函数部分,双参数的部分
			marksk.Push(data)
			result, resarr = createComp(arr[1:]) //函数都会带括号
			numsk.Push(result)
			arr = resarr
			result, resarr = createComp(arr)
			numsk.Push(result)
			arr = resarr
		} else {
			switch data {
			case "(":
				//要嵌套调用
				result, resarr = createComp(arr)
				numsk.Push(result)
				arr = resarr
			case ")", ",":
				//结束当前调用
				break arrfor
			case "-", "+", "*", "/", "%":
				//符号
				if marksk.Len() == 0 {
					marksk.Push(data)
				} else {
					curpt := checkPriority(data)
					for numsk.Len() >= 2 {
						propt := checkPriority(marksk.Get())
						//优先级
						if curpt <= propt {
							num2, num1 := numsk.Pop(), numsk.Pop()
							mark := marksk.Pop()
							cn := new(CompNode)
							cn.Num1 = num1
							cn.Num2 = num2
							cn.Mark = mark
							numsk.Push(cn)
						} else {
							break
						}
					}
					marksk.Push(data)
				}
			default:
				//数值
				cn := newComp(data)
				numsk.Push(cn)
			}
		}

	}
	for numsk.Len() >= 2 {
		num2, num1 := numsk.Pop(), numsk.Pop()
		mark := marksk.Pop()
		cn := new(CompNode)
		cn.Num1 = num1
		cn.Num2 = num2
		cn.Mark = mark

		numsk.Push(cn)
	}
	cn := numsk.Get()
	return cn, arr
}

// 栈结构，用于存储计算节点
type Stack []*CompNode

// 获取栈的长度
func (sk Stack) Len() int {
	return len(sk)
}

// 将计算节点压入栈
func (sk *Stack) Push(v *CompNode) {
	*sk = append(*sk, v)
}

// 从栈中弹出计算节点
func (sk *Stack) Pop() (result *CompNode) {
	result = (*sk)[sk.Len()-1]
	*sk = (*sk)[:sk.Len()-1]
	return
}

// 判断栈是否为空
func (sk Stack) IsEmpty() bool {
	return len(sk) == 0
}

// 获取栈顶的计算节点
func (sk Stack) Get() (result *CompNode) {
	return sk[sk.Len()-1]
}

// 栈结构，用于存储运算符
type StackMark []string

// 获取栈的长度
func (sk StackMark) Len() int {
	return len(sk)
}

// 将运算符压入栈
func (sk *StackMark) Push(v string) {
	*sk = append(*sk, v)
}

// 从栈中弹出运算符
func (sk *StackMark) Pop() (result string) {
	result = (*sk)[sk.Len()-1]
	*sk = (*sk)[:sk.Len()-1]
	return
}

// 判断栈是否为空
func (sk StackMark) IsEmpty() bool {
	return len(sk) == 0
}

// 获取栈顶的运算符
func (sk StackMark) Get() (result string) {
	return sk[sk.Len()-1]
}
